/**
 * @file 数组相关api
 */

import { cloneDeep } from 'lodash-es'
import { isEmpty, isNotEmpty } from './types'

/**
 * 扁平化数组 ==> 树形结构。 pid 为空时（使用isEmpty判断或者为0时），代表是一级
 * @param {array} list 扁平数组
 * @param {object} options 配置
 * @param {string} options.id 当前节点代表自己ID的key
 * @param {string} options.pid 当前接待代表父级ID的key
 * @param {string} options.childKey 当前节点子级树存放的key
 * @returns {array} 不影响原数组，返回处理后的数组
 *
 * @example
 * flatToTree(
 *  [{"id":"2","rank":1,"pid":""},{"id":"2.1","rank":2,"pid":"2"}],
 *  {id: 'id', pid: 'pid', childKey: 'children'}
 * )
 * // => [{"id":"2","rank":1,"pid":"","children":[{"id":"2.1","rank":2,"pid":"2","children":[]}]}]
 */
export const flatToTree = (list, options) => {
  const { childKey, pid, id } = options
  const newArr = cloneDeep(list)
  return newArr.filter(item => {
    const child = newArr.filter(childItem => childItem[pid] === item[id])
    item[childKey] = child
    return isEmpty(item[pid]) || item[pid] === 0
  })
}

/**
 * 树形结构 ==> 扁平化数组。 会删除 childKey 的键名
 * @param {Array} array 数组
 * @param {String} childKey 子集数组名
 * @param {Number} level 层级，不传代表支持无线层级
 * @param {Boolean} isDeleteChild 是否删除 childKey 键，默认删除
 * @returns {array} 不影响原数组，返回处理后的数组
 *
 * @example
 * treeToFlat([{"id":"2","rank":1,"children":[{"id":"2.1","rank":2}]}], 'children')
 * // => [{"id":"2","rank":1},{"id":"2.1","rank":2}]
 */
export const treeToFlat = (arr, childKey, level, isDeleteChild = true) => {
  const newArr = []
  let floor = 1
  function getData(list, _pid) {
    list.forEach(item => {
      const newItem = cloneDeep(item)
      if (isDeleteChild) {
        delete newItem[childKey]
      }
      newArr.push({ ...newItem, _pid })
      if (isNotEmpty(item[childKey])) {
        floor += 1
        if (level && floor > level) {
          return
        }
        getData(item[childKey], item.id)
      }
    })
  }
  getData(arr)
  return newArr
}

/**
 * 修改树形中某个Item的值（仅修改单个属性）
 * @param {Object} param
 * @param {Array} param.tree 要被修改的树形数据
 * @param {Array} param.id 要修改的Item的ID
 * @param {any} param.changeKey 要修改的Item的那个属性
 * @param {any} param.value 要修改的Item的那个属性修改后的值
 * @param {string} [param.idKey = 'id'] ID所属的字段名，默认为 'id'
 * @param {string} [param.childKey = 'children'] children所属的字段名，默认为 'children'
 * @returns
 */
export const changeTreeDataSingle = ({
  tree,
  id,
  value,
  changeKey,
  idKey = 'id',
  childKey = 'children',
}) => {
  // 源数据都没，改个毛
  if (isEmpty(tree)) {
    return []
  }

  // 啥东西都不提供，改个毛
  if (isEmpty(id) || isEmpty(value) || isEmpty(changeKey)) {
    return tree
  }

  // 深拷贝一份，因为我要直接改里面属性
  const newTree = cloneDeep(tree)

  // 根节点，就别递归了
  if (newTree[0][idKey] === id) {
    newTree[0][changeKey] = value
    return newTree
  }

  // 递归代码核心
  const searchTree = (source, searchId) => {
    for (let i = 0; i < source.length; i++) {
      const item = source[i]
      if (item[idKey] === searchId) {
        item[changeKey] = value
        return
      }

      // 有孩子才继续递归
      if (isNotEmpty(item[childKey])) {
        searchTree(item[childKey], searchId)
      }
    }
  }

  // 冲
  searchTree(newTree[0][childKey], id)
  return newTree
}
